package zheng.mockit.utils;

import com.ctc.wstx.stax.WstxInputFactory;
import com.ctc.wstx.stax.WstxOutputFactory;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.dataformat.xml.XmlFactory;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import com.fasterxml.jackson.dataformat.xml.ser.ToXmlGenerator;
import com.fasterxml.jackson.module.jaxb.JaxbAnnotationIntrospector;
import org.apache.commons.lang.StringUtils;

import java.io.IOException;
import java.util.List;

/**
 * Created by zcz on 2017/6/22.
 */
public class JacksonUtils {

    private static ObjectMapper jsonMapper;
    private static XmlMapper xmlMapper;

    static {
        jsonMapper = new ObjectMapper();
        jsonMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
        jsonMapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
        jsonMapper.disable(MapperFeature.DEFAULT_VIEW_INCLUSION);

        XmlFactory factory = new XmlFactory(new WstxInputFactory(), new WstxOutputFactory());
        xmlMapper = new XmlMapper(factory);
        xmlMapper.configure(ToXmlGenerator.Feature.WRITE_XML_DECLARATION, true);
        xmlMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
        xmlMapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
        //xmlMapper.enable(MapperFeature.USE_WRAPPER_NAME_AS_PROPERTY_NAME);
        xmlMapper.setAnnotationIntrospector(new JaxbAnnotationIntrospector(xmlMapper.getTypeFactory()));
    }

    /**
     * 将json转转化为bean
     *
     * @param json json文本
     * @param type bean类型
     * @return
     */
    public static <T> T jsonToBean(String json, Class<T> type) {
        return toBean(jsonMapper, json, type);
    }

    /**
     * 根据指定的视图构建对象
     *
     * @param json      json文本
     * @param type      bean类型
     * @param viewClass 视图类型
     * @return
     */
    public static <T> T jsonToBean(String json, Class<T> type, Class viewClass) {
        T result = null;
        try {
            if (StringUtils.isNotBlank(json)) {
                result = jsonMapper.readerWithView(viewClass).forType(type).readValue(json);
            }
            return result;
        } catch (Exception e) {
            throw new RuntimeException("Error converting to obj: " + json, e);
        }
    }


    /**
     * 将json转转化为bean
     *
     * @param xml  xml文本
     * @param type bean类型
     * @return
     */
    public static <T> T xmlToBean(String xml, Class<T> type) {
        return toBean(xmlMapper, xml, type);
    }

    /**
     * 将json转转化为bean。处理复杂的List或Map的转化。
     * 如new TypeReference<List<MyBean>>()
     *
     * @param json          json文本
     * @param typeReference bean类型
     * @return
     */
    public static <T> T jsonToBean(String json, TypeReference<T> typeReference) {
        return toBean(jsonMapper, json, typeReference);
    }

    /**
     * 将json转化为泛型的list。
     *
     * @param json json文本
     * @param type bean类型
     * @return
     * @throws java.io.IOException
     */
    public static <T> List<T> jsonToListBean(String json, Class<T> type) throws IOException {
        JavaType collectionType = jsonMapper.getTypeFactory().constructCollectionType(List.class, type);
        List<T> result = null;
        if (StringUtils.isNotBlank(json)) {
            result = jsonMapper.readValue(json, collectionType);
        }
        return result;
    }

    /**
     * 将xml转转化为bean。处理复杂的List或Map的转化。
     * 如new TypeReference<List<MyBean>>()
     *
     * @param xml           xml文本
     * @param typeReference bean类型
     * @return
     */
    public static <T> T xmlToBean(String xml, TypeReference<T> typeReference) {
        return toBean(xmlMapper, xml, typeReference);
    }

    /**
     * 将xml转化为泛型的list。
     *
     * @param xml  xml文本
     * @param type bean类型
     * @return
     * @throws IOException
     */
    public static <T> List<T> xmlToListBean(String xml, Class<T> type) throws IOException {
        JavaType collectionType = xmlMapper.getTypeFactory().constructCollectionType(List.class, type);
        List<T> result = null;
        if (StringUtils.isNotBlank(xml)) {
            result = xmlMapper.readValue(xml, collectionType);
        }
        return result;
    }

    /**
     * 将对象转成json
     *
     * @param obj 对象
     * @return
     */
    public static String toJson(Object obj) {
        return toString(jsonMapper, obj);
    }

    /**
     * 将对象转成json
     *
     * @param obj       对象
     * @param viewClass 视图对象
     * @return
     */
    public static String toJson(Object obj, Class viewClass) {
        return toStringWithView(jsonMapper, obj, viewClass);
    }

    /**
     * 将对象转成json
     *
     * @param obj       对象
     * @param viewClass 视图对象
     * @return
     */
    public static String toJsonList(Object obj, Class viewClass) {
        String result = null;
        try {
            if (obj != null) {
                result = jsonMapper.writerWithView(viewClass).writeValueAsString(obj);
            }
            return result;
        } catch (Exception e) {
            throw new RuntimeException("Error converting to str: " + obj, e);
        }
    }

    public static String toStringWithView(ObjectMapper mapper, Object obj, Class viewClass) {
        String result = null;
        try {
            if (obj != null) {
                result = mapper.writerWithView(viewClass).writeValueAsString(obj);
            }
            return result;
        } catch (Exception e) {
            throw new RuntimeException("Error converting to str: " + obj, e);
        }
    }

    /**
     * 将对象转成xml
     *
     * @param obj 对象
     * @return
     */
    public static String toXml(Object obj) {
        return toString(xmlMapper, obj);
    }

    private static String toString(ObjectMapper mapper, Object obj) {
        String result = null;
        try {
            if (obj != null) {
                result = mapper.writeValueAsString(obj);
            }
            return result;
        } catch (Exception e) {
            throw new RuntimeException("Error converting to str: " + obj, e);
        }
    }

    private static <T> T toBean(ObjectMapper mapper, String str, Class<T> type) {
        T result = null;
        try {
            if (StringUtils.isNotBlank(str)) {
                result = mapper.readValue(str, type);
            }
            return result;
        } catch (Exception e) {
            throw new RuntimeException("Error converting to obj: " + str, e);
        }
    }

    public static <T> T toBean(ObjectMapper mapper, String str, TypeReference<T> typeReference) {
        T result = null;
        try {
            if (StringUtils.isNotBlank(str)) {
                result = mapper.readValue(str, typeReference);
            }
        } catch (Exception e) {
            throw new RuntimeException("Error converting to obj: " + str, e);
        }
        return result;
    }

}
